WordPress Metabox is an additional content that can be added for any post type (post, page or custom). Every metabox can be used to display some information or to enable the user to insert additional information. In this tutorial we will learn how to easily create additional metaboxes using object oriented programming (OOP).
Code used in this tutorial can be used in any of your personal or commercial project.
Adding the WordPress Metabox
WordPress metabox can be added using the WordPress API function add_meta_box. This function will add the metabox to the edit screen of the post type for which we registered it. We will use these parameters:
- $id – Metabox unique identificator
- $title – Title that will be displayed on the metabox
- $callback – function that will render the content inside the metabox
- $context – this is used to control the position (normal, side or advanced) of the metabox
- $priority – this determines the order of the metabox (default, high or low)
Saving the WordPress Metabox
When we create additional fields in the metabox, we need to save those values when the post type is published or updated. This can be done using the action hook save_post.
Creating our WordPress Metabox
We will create our WordPress Metabox and the appropriate fields by using an abstract class that we have created in an article before where we have learned how to create WordPress menu pages with OOP. If you have followed that article and learned how to create the menu pages using the abstract class then you will understand the code of our abstract class.
We have used this abstract class in another article before where we have also learned how to create custom WordPress profile fields. If you have that abstract class WordPressSettings, then you can just click here to jump to the rest of the content.
If you have some spare time, please read the article about creating menu pages so that you can understand what the abstract class does. If you do not have time at this moment, then you can just copy the code from here:
WordPress Metabox Class
We will now begin to code our metabox class by extending our abstract class. We will have to modify some of the inherited methods:
- init_settings() – get the settings using the get_post_meta
- save_settings() – save the settings using the update_post_meta
First, we will define our attributes:
Most of the defined attributes are the attributes we have described above as the metabox parameters. The only new attributes are the $post_id used to save the settings for that content and the array $post_types that defines for which content our metabox will be displayed.
Now let’s define our constructor method that will set every attribute and also hook into the appropriate WordPress action hooks.
In these method we will first check if everything is set as it should be. The metabox will not be created if the $slug, $context or $priority is empty. Also if there is not post type defined for which we will create the metabox, the metabox will not be created. If for some reason the title is not set, we will create it from the slug.
We are adding the method register to the action hook add_meta_boxes and also the method save_meta_settings to the action hook save_post.
Let’s define our method register that is used to add our metabox:
Here we check if the provided post type ($post_type) is also in our array of allowed post types ($post_types). If it is, then we are adding our metabox.
Rendering the WordPress Metabox
In the function add_meta_box we also pass a method render which is used to render the content of our metabox. Let’s define it now:
In this method we set the post ID to our attribute $post_id and then we are also calling a method init_settings to retrieve our settings so that each of our defined fields can be populated with the according value.
Once that is done, we are creating a hidden nonce field using the WordPress API function wp_nonce_field. This will make our metabox more secure as we will allow saving the settings only from the admin area. After that we are rendering our fields with the method render_fields by passing the tab general because we are using here only one tab.
If we are to create more tabs, we would need to implement some JavaScript functionality. This could be covered in a new article, so be sure to subscribe if you want to get notified:)
The method init_settings used in the method render will need to be modified so that we can retrieve our metabox values:
The only thing that we had changed here from the abstract class are the first few lines where we get the $post_id and also use the function get_post_meta. The rest of the code in this method is described in the previous article where we have created the abstract class. But to summarize, we set the value for each registered field from the the retrieved data.
Saving our WordPress Metabox
To save our metabox we have hooked our method save_meta_settings to the hook save_post. Here is the definition of that method:
We are first verifying the nonce we have set when rendering our metabox. Once that is verified, we are making sure that the user has the permission to save the post. If everything checks, we are setting the post ID to our attribute $post_id. After that we are calling the method save_settings().
Since the method save_settings is a method inherited from the abstract class, we have to modify it a little bit so that we can save the post meta:
The modified part in this method is the last line where we save our settings using the WordPress API function update_post_meta.
Using our WordPress Metabox
To show you how you could use the metabox values I will create a redirect field where we can insert an URL. If there is an URL inserted, we will redirect our visitor to that page.
First we need to create our metabox and add the field:
Now that we have defined our metabox and also added our field for the redirect URL, we need to check for that URL.
We are here getting the extra settings and we are checking if the setting redirect_url is set and not empty. If that is the case, we will redirect our user to that URL. Please do note that this code is not bulletproof and it is used as a showcase. Not recommended for production.
By following the code usage in this example you can create as many metaboxes as you need.
Conclusion
Using the abstract class that we have defined before, we can easily add new fields and metaboxes to our post types by just modifying 2 inherited methods. Metaboxes are a great way to add any new data or information that we need for our post type so by using OOP we are removing any repetitive code that we need to enter for adding metaboxes and fields.
I am sure you had some experience with using metaboxes. Please share them in the comments below or ask a question;)
Read this article even when offline on your Kindle, Tablet or Smartphone in my eBook “Practical WordPress“. Subcribe to get this book for FREE.
Become a Sponsor
I’m trying to get this to work, but so far, the only post_meta “key” that is being saved isn’t coming from the ‘name’ field under add_field. The meta key is saved using ‘extra_settings’, and under that, it’s only saving the first letter of the meta_value.
Then it’s also not read back in when re-displaying the box. I’m going through the code, maybe I’ll find it before you answer back.
Hi Thomas, have you found out what was wrong?
I have not. It works beautifully on another WP install. I’ve tried disabling all other plugins, (including mu-plugins) gone to a generic theme, (twentyseventeen) overwriting all wp core files, and even a fresh database as a test. Even have tried going back to php 5.6. I’ve tested with various die () statements after output, and I get quite a few unknown index warnings on “redirect_url” before the refresh.
Also, the menu boxes using the same abstract class, also works very well.
I’ve spent days on this, because I haven’t found another library I consider as simple and clean.
Hi Thomas, so what you’re saying is that on another installation it works without issues, but on yours, it won’t work? Really weird. I’ll try to test everything once more on a new fresh install in a few days to see what is going on.
Last night I sat back down with it, took out all my breakpoints, and deleted the postmeta field, and suddenly it worked just fine. I would say it was just struggling with a bad existing postmeta, but I’d also tried a blank database a couple times… Things that make you go Hmmm…
So it’s working now. I’m a little disappointed that it saves all the values as a single meta value, (serialized array) but I’ll play with that. Granted it’s often easier to load/save a bunch of values at once, but, I have need to search by a meta value.
Additional field types should also be easy enough.
I thank you for sharing your technique!
Hi Thomas, if you want to save meta fields as single meta records. You can do that also. See how I refactored this class in my Simple Giveaways plugin. If I set property ‘single’ to true, I save that field with update_post_meta. https://plugins.trac.wordpress.org/browser/giveasap/trunk/includes/giveasap-metabox.php#L296
Completely useless class and lost time. To work it needs WooCommerce (uses the wc_clean method to validate the fields) which makes it impossible to use it for other purposes.
Thanks for wasting my time.
Hi Marco, sorry for that. I’ve removed the wc_clean reference form the code now. That should not have been there and I did think I removed all of them. It should be fine now 🙂
Completely useless person and waste of space. To work it needs a brain (uses google to do his job for him) which makes it improbable that he will ever amount to anything useful.
We have experienced the same issue as described above by @Thomas
We have installed on two seperate development servers, using two different themes.
The Meta box value is not being saved correctly; it saves only the first character to the DB and does not retrieve after save.
We logged a PHP Warning: Illegal string offset – occurring in the abstract method ‘get_option()’ – something is trying to treat a string as an array…
Uninterestingly, the fields $defaults Array contains the ‘default’ key twice.
PHP 7+ WP 5.1+ with classic editor and without… all plugins uninstalled – Twenty Sixteen theme.
Email us if you would like to debug in the wild – though it’s Friday here… and my girlfriend wants pizza… so there’s that
Hi Duncan, that might be due to the option that is retrieved in the database. I’ve experienced that when I was tweaking the value in the database and then trying to get it through this class.
I’ll have to go through this and check if it comes up on my side as well. Maybe something is done differently on WP 5.1 but it should not be.
I’ve experienced the same issue written by other ones, I debugged the code and found that the problem is in the init_settings method on this line:
$this->settings = get_post_meta( $post_id, $this->settings_id, true );
This one retrieve only the value of the of the first one, if you change to false the third parameter of get_post_meta the problem persist. I solved with casting the variable, like this:
$this->settings = (array) get_post_meta( $post_id, $this->settings_id, true );
This do the trick, but the first time init_settings is called it store an empty value in the array so I put an if condition to avoid it:
if ( ” !== get_post_meta( $post_id, $this->settings_id, true ) ) {
$this->settings = (array) get_post_meta( $post_id, $this->settings_id, true );
}
Can this be a good solution?
Hi Manuel, it could be a fine solution.
I am currently on a vacation and I’ll be back next week. You can ping me then if I don’t reply to you by Thursday.
I’ll check the code that I am using for my Simple Giveaways plugin which used the same code. But I could have changed something after using this code.
i spent 2 hours to fix all of error
– save only 1 letter
– Illegal string offset
it cause by php 7 require define array variable before use.